//
// Created by denglibin on 2021/9/6.
//
#include "02_singal_event.h"
#include "init.h"
#include "log.h"
#include <event2/thread.h>
#include <event2/listener.h>
#include <stdlib.h>
#define SPORT 5001

static struct timeval t1 = {1, 0};
/**
 * Ctrl+C 事件回调函数
 * @param sock 文件描述符
 * @param which 事件类型
 * @param arg  自定义的参数
 */
static void Ctrl_C(int sock, short which, void* arg);
/**
 * kill 事件回调函数
 * @param sock
 * @param which
 * @param arg
 */
static void Kill(int sock, short which, void* arg);


/**
 * 接收到连接的回调函数
 * @param evconnlistener
 * @param fd
 * @param addr
 * @param socklen
 * @param arg
 */
static void listen_cb(struct evconnlistener * evconnlistener, evutil_socket_t fd, struct sockaddr * addr, int socklen, void * arg);


/**
 * 定时器回调
 * @param sock
 * @param which
 * @param arg
 */
static void timer1(int sock, short which, void* arg);
/**
 * 定时器回调
 * @param sock
 * @param which
 * @param arg
 */
static void timer2(int sock, short which, void* arg);

/**
 * 定时器回调
 * @param sock
 * @param which
 * @param arg
 */
static void timer3(int sock, short which, void* arg);

/**
 * 创建配置
 * @return
 */
static struct event_config * get_event_config(){
    //创建配置
    struct event_config * conf = event_config_new();

#ifdef _WIN32
    //windows下使用iocp, 内部使用线程池
    event_config_set_flag(conf, EVENT_BASE_FLAG_STARTUP_IOCP);
    //初始化iocp的线程
    int r = evthread_use_windows_threads();
    if(r != 0){
        fprintf(stderr, "evthread_use_windows_threads() fail!");
        return NULL;
    }
    SYSTEM_INFO si;
    GetSystemInfo(&si); //获取系统信息
    //设置cpu数量
    event_config_set_num_cpus_hint(conf, si.dwNumberOfProcessors);

#endif

    //设置特征(windows不支持)
    //event_config_require_features(conf,  EV_FEATURE_ET);
    return conf;
}

/**
 * 创建event_base
 * @return
 */
static struct event_base * get_event_base(){
    struct event_config* conf = get_event_config();
    if(conf == NULL){
        fprintf(stderr, "get_event_config() fail!");
        return NULL;
    }
    //使用配置初始化上下文
    struct event_base * base = event_base_new_with_config(conf);
    //释放
    event_config_free(conf);
    if(!base) {
        fprintf(stdout, "event_base_new_with_config fail!");
        return NULL;
    }
    //显示支持的网络模式
    const char** methods = event_get_supported_methods();
    //windows -> win32
    //linux -> epoll,poll, select (epoll优先，然后poll,最后select)
    for(int i = 0; methods[i] != NULL; i++) {
        printf("support method: %s\n", methods[i]);
    }

    //获取当前网络模型 window->win32 linux->epoll
    const char* method = event_base_get_method(base);
    printf("current method: %s\n", method);

    //确认特征是否生效(windows下都不行)
    int f = event_base_get_features(base);
    if(f & EV_FEATURE_ET) { //边沿触发
        printf("EV_FEATURE_ET supported\n");
    }
    if(f & EV_FEATURE_O1){
        printf("EV_FEATURE_O1 supported\n");
    }
    if(f & EV_FEATURE_FDS){
        printf("EV_FEATURE_FDS supported\n");
    }
    if(f & EV_FEATURE_EARLY_CLOSE){
        printf("EV_FEATURE_EARLY_CLOSE supported\n");
    }
    return base;
}

/**
 * 监听端口
 * @param base
 * @return
 */
static struct evconnlistener * listen_port(struct event_base* base){
    //socket设置
    struct sockaddr_in sin;
    memset(&sin, 0, sizeof(sin));
    sin.sin_family = AF_INET;
    sin.sin_port = htons(SPORT);

    printf("listen port:%d\n", SPORT);
    //监听端口
    struct evconnlistener * listener = evconnlistener_new_bind(base,
                                                               listen_cb,                                       //回调函数
                                                               base,                                            //自定义数据
                                                               LEV_OPT_REUSEABLE | LEV_OPT_CLOSE_ON_FREE, //地址重用，listen关闭socket
                                                               10,                                      //连接缓冲队列大小
                                                               (struct sockaddr*)&sin,                          //端口
                                                               sizeof(sin));
    return listener;
}

void listen_cb(struct evconnlistener * evconnlistener, evutil_socket_t fd, struct sockaddr * addr, int socklen, void * arg){
    printf("listen_cb\n");
}

void Ctrl_C(int sock, short which, void* arg){
    printf("==============>Ctrl_C, shutdown program\n");
    exit(0);
    //Ctrl+z挂起 pkill -9 程序名 杀掉进程
}
void Kill(int sock, short which, void* arg){
    printf("==============>Kill\n");
    struct event* event = (struct event*)arg;
    if(!evsignal_pending(event, NULL )){
        event_del(event);
        //再次添加
        event_add(event, NULL);
    }
}

void timer1(int sock, short which, void* arg){
    zlog_info(log_get_zlog_c(),"timer1...");
    struct event* e = (struct event*)arg;
    if(!evtimer_pending(e, &t1)){
        evtimer_del(e);
        evtimer_add(e, &t1); //再次添加
    }
}
void timer2(int sock, short which, void* arg){
    zlog_info(log_get_zlog_c(),"timer2...");
}
void timer3(int sock, short which, void* arg){
    zlog_info(log_get_zlog_c(),"timer3...");
}

int demo_2(){
    init();
    struct event_base * base = get_event_base();
    if(base == NULL){
        fprintf(stderr, "get_event_base fail!\n");
        clean();
        return -1;
    }
    struct evconnlistener * listener = listen_port(base);
    //事件分发处理
    printf("event_base_dispatch...\n");
    event_base_dispatch(base);
    //释放
    evconnlistener_free(listener);
    event_base_free(base);
    clean();
    return 0;
}

void signal_event_demo(){
#ifndef _WIN32
    init();
    log_zlog_info("signal_event_demo...");
    struct event_base* base = event_base_new();
    //ctrl+c 信号事件 no pending 状态
    struct event* csig = evsignal_new(base, SIGINT,Ctrl_C, base);
    if(!csig){
        clean();
        fprintf(stderr, "SIGINT evsignal_new() fail\n");
        return;
    }

    //添加事件 进入 pending状态
    if(event_add(csig, NULL) != 0) {
        clean();
        fprintf(stderr, "SIGINT event_add() fail\n");
        return;
    }

    //kill信号事件，非持久事件，只进入一次,  event_self_cbarg()传递当前的event
    struct event* ksig = event_new(base, SIGTERM, EV_SIGNAL, Kill, event_self_cbarg());
    //添加事件
    if(event_add(ksig, NULL) != 0) {
        clean();
        fprintf(stderr, "SIGTERM event_add() fail\n");
        return;
    }

    //进入事件循环
    event_base_dispatch(base);

    event_free(csig);
    //释放
    event_base_free(base);
    clean();
#endif
}

void timer_demo(){
#ifndef _WIN32
    init();
    zlog_info(log_get_zlog_c(),"timer demo...");
    struct event_base* base = event_base_new();

    //定时器1 事件,非持久事件，只进入一次
    struct event* e = evtimer_new(base, timer1, event_self_cbarg());
    if(!e){
        zlog_error(log_get_zlog_c(),"evtimer_new fail");
        goto  END;
    }
    //定时器
    evtimer_add(e, &t1);


    struct timeval t2 = {1, 0};
    //定时器2 事件， 持久
    struct event* e2 = event_new(base, -1, EV_PERSIST, timer2, NULL);
    //定时器
    evtimer_add(e2, &t2);

    //定时器3
    struct timeval tv_in = {3, 0};
    const struct timeval* t3 = event_base_init_common_timeout(base, &tv_in);
    struct event* e3 = event_new(base, -1, EV_PERSIST, timer3, NULL);
    event_add(e3, t3);

    //进入事件循环
    event_base_dispatch(base);

    END:
        //释放
        event_base_free(base);
        clean();
#endif
}

